package ${package}.${rootArtifactId}.util;

import cn.hutool.core.util.RandomUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.platform.commons.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Description: 对象工具
 * @author weidong.lin
 * @date 2021/8/2 17:56
 */
public class ObjectUtil {

    /**
     * 随机赋值,仅限单测造数据使用
     *
     * @param obj obj
     * @return obj
     */
    public static <T> T getObjDefault(T obj) {
        // 得到类对象
        Class<?> objCla = obj.getClass();
        Field[] fs = objCla.getDeclaredFields();
        String str = null;
        Integer integer = null;
        Double adouble = null;

        for (Field f : fs) {
            // 设置些属性是可以访问的
            boolean isStatic = Modifier.isStatic(f.getModifiers());
            if (isStatic) {
                continue;
            }
            // 设置些属性是可以访问的
            f.setAccessible(true);
            try {
                // 得到此属性的值
                Object val = f.get(obj);
                // 得到此属性的类型
                String type = f.getType().toString();
                boolean isInt = (type.endsWith("int") || type.endsWith("Integer"));
                boolean isDouble = (type.endsWith("double") || type.endsWith("Double"));
                boolean isLong = (type.endsWith("long") || type.endsWith("Long"));
                boolean isShort = (type.endsWith("short") || type.endsWith("Short"));
                boolean isByte = (type.endsWith("byte") || type.endsWith("Byte"));
                if (type.endsWith("String") && val == null) {
                    if (StringUtils.isBlank(str)) {
                        str = RandomUtil.randomString(5);
                    }
                    f.set(obj, str);
                } else if (isInt && val == null) {
                    if (null == integer) {
                        integer = RandomUtil.randomInt(1, 100);
                    }
                    f.set(obj, integer);
                } else if (isDouble && val == null) {
                    if (null == adouble) {
                        adouble = RandomUtil.randomDouble(100, 1, RoundingMode.HALF_DOWN);
                    }
                    f.set(obj, adouble);
                } else if (isLong && val == null) {
                    f.set(obj, 0L);
                } else if (isShort && val == null) {
                    f.set(obj, (short) 0);
                } else if (type.endsWith("List") && val == null) {
                    f.set(obj, Lists.newArrayList());
                } else if (type.endsWith("Date") && val == null) {
                    f.set(obj, Date.valueOf("1970-01-01"));
                } else if (type.endsWith("Timestamp") && val == null) {
                    f.set(obj, Timestamp.valueOf("1970-01-01 00:00:00"));
                } else if (type.endsWith("BigDecimal") && val == null) {
                    f.set(obj, new BigDecimal(0));
                } else if (isByte && val == null) {
                    f.set(obj, RandomUtil.randomBytes(2)[0]);
                }
            } catch (Exception e) {
            }
        }
        return obj;
    }

    protected <T> T instance(Class<T> tClass) throws IllegalAccessException, InstantiationException {
        T newInstance = tClass.newInstance();
        Field[] fields = tClass.getDeclaredFields();
        if (fields.length == 0) {
            return newInstance;
        }
        for (Field field : fields) {
            if (Modifier.isFinal(field.getModifiers())) {
                continue;
            }
            field.setAccessible(true);
            Class<?> fieldType = field.getType();
            if (Long.class.equals(fieldType) || Long.TYPE.equals(fieldType)) {
                field.set(newInstance, 1L);
            } else if (Integer.class.equals(fieldType) || Integer.TYPE.equals(fieldType)) {
                field.set(newInstance, 1);
            } else if (Boolean.class.equals(fieldType) || Boolean.TYPE.equals(fieldType)) {
                field.set(newInstance, Boolean.TRUE);
            } else if (Double.class.equals(fieldType) || Double.TYPE.equals(fieldType)) {
                field.set(newInstance, 0.0);
            } else if (Float.class.equals(fieldType) || Float.TYPE.equals(fieldType)) {
                field.set(newInstance, 0.0F);
            } else if (String.class.equals(fieldType)) {
                field.set(newInstance, "0");
            } else if (java.util.Date.class.equals(fieldType)) {
                field.set(newInstance, new java.util.Date());
            } else if (BigDecimal.class.equals(fieldType)) {
                field.set(newInstance, BigDecimal.ZERO);
            } else if (List.class.equals(fieldType)) {
                Type genericType = field.getGenericType();
                if (genericType == null) {
                    field.set(newInstance, null);
                }
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) genericType;
                    // 得到泛型里的class类型对象
                    Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
                    Object actualType = instance(actualTypeArgument);
                    field.set(newInstance, Lists.newArrayList(actualType));
                }
            } else if (Set.class.equals(fieldType)) {
                Type genericType = field.getGenericType();
                if (genericType == null) {
                    field.set(newInstance, null);
                }
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) genericType;
                    // 得到泛型里的class类型对象
                    Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
                    Object actualType = instance(actualTypeArgument);
                    field.set(newInstance, Sets.newHashSet(actualType));
                }
            } else if (Map.class.equals(fieldType)) {
                field.set(newInstance, new HashMap<>(2));
            } else {
                field.set(newInstance, null);
            }
        }
        return newInstance;
    }
}
